#-----------------------------------------------------------------------------
# Name:        tap.py
# Purpose:     
#
# Author:      Roger Jarvis
#
# Created:     2008/10/08
# RCS-ID:      $Id: tap.py $
# Copyright:   (c) 2008
# Licence:     GNU General Public License
#-----------------------------------------------------------------------------
import wx
import wx.lib.filebrowsebutton
import wx.lib.wordwrap
import wx.lib.buttons
import wx.lib.newevent
import wx.lib.masked
import wx.lib.foldpanelbar as fpb
import wx.wizard

from omixed import omixed
from wx.lib.anchors import LayoutAnchors
import wx.lib.delayedresult as delayedresult
from xml.dom import minidom

import os
import shutil
import stat
import string
import thread
import datetime
import time

[AboutId, RestoreId, ExitId, ConnectId, LoadId, SendAllId, SendId,
TbQueueId, TbFailId, TbAcquireId, MenuCfId, MenuRaId, StudySubId, 
SetComboId, ExpSubId, InstChoiceId, ExpsComboId, StudyChId, SetWizId, 
WizId, TxtFileManId, StartSessId, PollIntId, WizBtnId, WizCancelId, 
WizBtnNextId, LboxId, RemoveId] = [wx.NewId() for _init_ctrls in range(28)]

(UpdateNotebookEvent, EVT_UPDATE_NOTEBOOK) = wx.lib.newevent.NewEvent()

def ExtractXmlForLists(node):
    #get lists of attributes where applicable
    listOptions = None
    if node.attributes["type"].value == 'LIST':
        listOptions = []
        for item in node.childNodes:
            listOptions.append(item.attributes["name"].value)
    return listOptions

def makePageTitle(wizPg, title):
    #create wizard page sizer
    sizer = wx.BoxSizer(wx.VERTICAL)
    wizPg.SetSizer(sizer)
    title = wx.StaticText(wizPg, -1, title)
    title.SetFont(wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD))
    sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
    sizer.Add(wx.StaticLine(wizPg, -1), 0, wx.EXPAND|wx.ALL, 5)
    return sizer

def getName(itemID):
    #recover item name from itemid
    iN = string.split(itemID,'/')
    return iN[len(iN)-1]

class Listbook(wx.Panel):
    def _init_sizer(self):
        #sizer for queue panel
        self.grdSizer = wx.GridBagSizer(hgap=4, vgap=4)
        self.grdSizer.SetCols(2)
        self.grdSizer.SetRows(1)
        
        self.grdSizer.AddWindow(self.listbox, (0, 0), border=0, flag=wx.EXPAND, 
              span=(1, 1))
        self.grdSizer.AddWindow(self.panel, (0, 1), border=0, flag=wx.EXPAND, 
              span=(1, 1))
        
        self.grdSizer.AddGrowableRow(0)
        self.grdSizer.AddGrowableCol(1)
        
        self.SetSizer(self.grdSizer)
        
    def _init_ctrls(self, prnt):
        wx.Panel.__init__(self, id=wx.NewId(), name='Listbook', parent=prnt,
              pos=wx.Point(-12, 22), size=wx.Size(1024, 599), style=wx.TAB_TRAVERSAL)
        self.SetAutoLayout(True)
        self.SetToolTipString('')
        
        #load and send buttons
        self.listbox = wx.ListBox(self, id=LboxId, style=wx.LB_HSCROLL | wx.LB_SINGLE)
        self.listbox.Bind(wx.EVT_LISTBOX, self.OnSelectFromList, id=LboxId)
        
        self.panel = wx.Panel(self, id=-1)
        self.panel.Show(False)
            
        self._init_sizer()
    
    def __init__(self, parent, stbar):
        self._init_ctrls(parent)
        
        self.stbar = stbar
        
        self.prnt = parent
        
        self.panelList = []
        
    def OnSelectFromList(self, event):
        sel = event.GetSelection()
        self.DoSelect(sel)
        
    def DoSelect(self, sel):
        if self.listbox.GetCount() > 0:
            #get current items from sizer
            items = self.grdSizer.GetChildren()
            
            #hide panel
            currPanel = items[1].GetWindow()
            currPanel.Show(False)
            
            #determine selected panel
            selPanel = self.panelList[sel]
            selPanel.Show(True)
            
            #replace in sizer
            self.grdSizer.Replace(currPanel, selPanel)
            
            #refresh layout
            self.grdSizer.Layout()
    
    def AddPage(self, panel, label):
        self.panelList.append(panel)
        self.listbox.Append(label)
        self.listbox.SetSelection(self.GetCount()-1)
        self.DoSelect(self.GetCount()-1)
        
    def DeletePage(self, sel):
        if sel < self.listbox.GetCount():
            delPanel = self.panelList.pop(sel)
            self.listbox.Delete(sel)
            #add dummy panel to sizer
            if self.listbox.GetCount() == 0: 
                #replace in sizer
                self.grdSizer.Replace(delPanel, self.panel)
                delPanel.SetSize((0,0))
            
            if sel > 0:
                self.DoSelect(sel-1)
            else:
                self.DoSelect(0)
            
            if delPanel != self.panel:
                #finally destroy panel
                delPanel.Destroy()
            else:
                delPanel.Show(False)
            
            #refresh layout
            self.grdSizer.Layout()
            self.Layout()
            
        #recalculate queue number
        self.stbar.SetStatusText('Acquired: ' + str(self.prnt.GetParent().tbFileAcquire.GetCount()),2)
        self.stbar.SetStatusText('Failed: ' + str(self.prnt.GetParent().tbFileFail.GetCount()),4)

            
    def GetCount(self):
        return self.listbox.GetCount()
    
    def GetCurrentPage(self):
        return self.panelList[self.listbox.GetSelection()]
    
    def GetPage(self, sel):
        return self.panelList[sel]
    
    def GetSelection(self):
        return self.listbox.GetSelection()
    
class ClearQueueThread:
    def __init__(self, parent, queuebk):
        self.prnt = parent
        self.queuebk = queuebk
        self.keepgoing = True
        self.running = False
        self.sending = False
    
    def Start(self):
        self.running = True
        thread.start_new_thread(self.Run, ())

    def Stop(self):
        self.keepgoing = False
    
    def IsSending(self):
        return self.sending
        
    def IsRunning(self):
        return self.running

    def Run(self):
        #process the file queue - send files to server
        last = ""
        while self.keepgoing:
            if self.queuebk.GetCount() > 0:
                page = self.queuebk.GetPage(0)
                if page.txtLabel != 'Queued Files':
                    label = page.txtLabel.GetValue()
                    if label not in [last]:
                        last = label
                        #send file
                        self.SendToServer(page)
                    
                #recalculate queue number
                self.prnt.statusbar.SetStatusText('Queued: ' + str(self.queuebk.GetCount()),3)
                self.prnt.statusbar.SetStatusText('Failed: ' + str(self.prnt.plFileHolder.tbFileFail.GetCount()),4)
            
                #time for a little rest
                time.sleep(1)
        
        self.running = False
        
    def SendToServer(self, page):
        try:
            #tell the app we're sending a file
            self.sending = True
            
            #set the gauge running
            page.gauge.Show(True)
            page.gauge.Pulse()
            
            #first of all connect to dbs
            client = self.prnt.TapConnect()
            
            #upload data file
            fileID = client.upload(page.txtFile.GetValue())   
            
            #create sample entry on dbs
            sampleItem = omixed.OmixedItem()
            sampleItem.setupNewItem(client, "Sample", page.txtLabel.GetValue(), 
                  "public")
            sampleItem.setAttribute ("void", "false")
            sampleItem.setAttribute ("label", page.txtLabel.GetValue())
            sampleItem.setAttribute ("description", page.txtDesc.GetValue())
            sampleItem.setAttribute ("datetime", string.join((page.txtDate.GetValue(),
                  'T',page.txtTime.GetValue(),'.000000'),''))
            
            #link file (assay) to sample
            assayItem = omixed.OmixedItem()
            assayItem.setupNewItem(client, "Assay", page.txtLabel.GetValue(), "public")
            assayItem.setAttribute ("user", self.prnt.plLoginManager.txtUser.GetValue())
            assayItem.setFileID("grams data file", fileID)
            assayItem.setLink("grams data file", fileID)
            assayItem.setLink ("Sample(assayed sample)", sampleItem.itemID)
            
            assayId = assayItem.itemID
            
            #link assay to experiment
            #generate expId
            expId = client.getDomainName() + '/' + \
                  self.prnt.plLoginManager.txtResource.GetValue() + \
                  '/Experiment/' + \
                  self.prnt.plLoginManager.txtUser.GetValue() + '/' + \
                  self.prnt.SettingsWiz.SettingsInfo.cbExperiments.GetValue()
            
            #create new items on dbs
            client.itemCreate(sampleItem)
            client.itemCreate(assayItem)
            
            #get exp item object
            expItem = client.itemFind(omixed.OmixedQuery.FULL_ITEM_DETAILS,"<ItemID>" + expId + "</ItemID>")[0]
            
            #link to assay
            expItem.setLink('has assay', assayId)
            
            #update exp on dbs
            client.lockAcquire(expItem.itemID)
            client.itemUpdate(expItem)
            
            #set the gauge to 100%
            page.gauge.SetValue(100)
            
            #disconnect
            client.disconnect()
            
        except Exception, error:
            #report error to status bar
            self.prnt.errorlist.Append(error.faultstring)
            self.prnt.errorlist.SetSelection(self.prnt.errorlist.GetCount()-1)
            
            #create failure nb page
#            FileHandlingPage(self.prnt.plFileHolder.tbFileFail, page.txtFile.GetValue(), 
#                  page.txtDate.GetValue(), page.txtTime.GetValue(), subbtn=True, 
#                  desc=page.txtDesc.GetValue(), label=page.txtLabel.GetValue())
            
        finally:
            #delete queued notebook page
            self.queuebk.DeletePage(0)
            
            #recalculate queue number
            self.prnt.statusbar.SetStatusText('Queued: ' + str(self.queuebk.GetCount()),3)
            self.prnt.statusbar.SetStatusText('Failed: ' + str(self.prnt.plFileHolder.tbFileFail.GetCount()),4)
            
            #tell app that file no longer being sent
            self.sending = False
            
class PollDirThread:
    def __init__(self, parent, interval):
        self.prnt = parent
        self.keepgoing = True
        self.running = False
        self.interval = interval
        
    def Start(self):
        self.running = True
        thread.start_new_thread(self.Run, ())
        
    def Stop(self):
        self.keepgoing = False

    def IsFileBeingSent(self):
        return self.prnt.sendThread.IsSending()
    
    def IsRunning(self):
        return self.running
    
    def Run(self):
        #search target directory for new files
        present = time.time()
        try:
            while self.keepgoing:
                while self.IsFileBeingSent():
                    time.sleep(0.1)
                currDir = self.prnt.plLoginManager.btnDir.GetValue()
                files = os.listdir(currDir)
                for each in files:
##                    if len(string.split(each,'.spc')) == 2: #only pick up .spc files
                    if (present < os.lstat(os.path.join(currDir,each)).st_ctime): #& \
##                          (each not in ['raman_manager_sent']):
                        evt = UpdateNotebookEvent(file = each)
                        wx.PostEvent(self.prnt, evt)
                present = time.time()
                time.sleep(self.interval)
                
        except Exception, error:
            raise
            dlg = wx.MessageDialog(self.prnt.frame, '%s' %str(error), 'Error!', 
                  wx.OK | wx.ICON_ERROR)
            try:
                dlg.ShowModal()
            finally:
                dlg.Destroy()
            self.prnt.statusbar.SetStatusText('RamanTap Inactive',0)
        
        self.running = False

class SettingsWizard(wx.Panel):
    def _init_sizer(self):
        self.grdSizer = wx.GridBagSizer(hgap=4, vgap=4)
        self.grdSizer.SetCols(4)
        self.grdSizer.SetRows(3)
        self.grdSizer.AddGrowableRow(0)
        self.grdSizer.AddGrowableCol(0)
#        self.grdSizer.AddGrowableCol(1)
#        self.grdSizer.AddGrowableCol(2)
#        self.grdSizer.AddGrowableCol(3)
        
        self.grdSizer.AddSpacer(wx.Size(4, 4), (1, 0), border=0, flag=0, span=(1,4))
        
        self._init_study_sizer()
        
    def _init_study_sizer(self):
        for item in self.grdSizer.GetChildren():
            if item.GetWindow() != None:
                self.grdSizer.Detach(item.GetWindow())
        self.grdSizer.DeleteWindows()
        
        self.grdSizer.AddWindow(self.StudyInfo, (0, 0), border=0, flag=wx.EXPAND, 
              span=(1, 4))
        self.grdSizer.AddWindow(self.btnNext, (2, 3), border=0, flag=wx.EXPAND, 
              span=(1, 1))
        
        self.btnFinish.Show(False)
        self.btnNext.Show(True)
        self.btnCancel.Show(False)
        self.SettingsInfo.Show(False)
        self.StudyInfo.Show(True)
        
        self.SetSizer(self.grdSizer)
        
        self.grdSizer.Layout()
        
    def _init_settings_sizer(self):
        for item in self.grdSizer.GetChildren():
            if item.GetWindow() != None:
                self.grdSizer.Detach(item.GetWindow())
        self.grdSizer.DeleteWindows()
        
        self.grdSizer.AddWindow(self.SettingsInfo, (0, 0), border=0, flag=wx.EXPAND, 
              span=(1, 4))
#        self.grdSizer.AddSpacer(wx.Size(4, 4), (1, 0), border=0, flag=0, span=(1,4))
        self.grdSizer.AddWindow(self.btnCancel, (2, 2), border=0, flag=wx.EXPAND, 
              span=(1, 1))
        self.grdSizer.AddWindow(self.btnFinish, (2, 3), border=0, flag=wx.EXPAND, 
              span=(1, 1))
        
        self.btnNext.Show(False)
        self.btnFinish.Show(True)
        self.btnCancel.Show(True)
        self.StudyInfo.Show(False)
        self.SettingsInfo.Show(True)
        
        self.SetSizer(self.grdSizer)
        
        self.grdSizer.Layout()
        
    def _init_ctrls(self, prnt, root):
        wx.Panel.__init__(self, id=WizId, pos=wx.Point(-1, -1), parent=prnt)
        
        self.btnCancel = wx.Button(self, id=WizCancelId, label='Cancel')
        self.btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel, id=WizCancelId)
        
        self.btnNext = wx.Button(self, id=WizBtnNextId, label='Next')
        self.btnNext.Bind(wx.EVT_BUTTON, self.OnNext, id=WizBtnNextId)
        
        self.btnFinish = wx.Button(self, id=WizBtnId, label='Finish')
        self.btnFinish.Bind(wx.EVT_BUTTON, self.OnFinished, id=WizBtnId)
        
        self.StudyInfo = StudyPanel(self, root)
        
        self.SettingsInfo = SettingsPanel(self, root)
        
        self._init_sizer()
        
    def __init__(self, parent, root):
        self._init_ctrls(parent, root)
        
        self.root = root
        
    def OnCancel(self, event):
        #update study options from dbs
        self.StudyInfo.Update()
        #update settings options from dbs
        self.SettingsInfo.Update()
        #disable file queue panel
        self.root.plFileHolder.Enable(False)
        #show study setup
        self._init_study_sizer()
        
    def OnNext(self, event):
        self._init_settings_sizer()
        
    def OnFinished(self, event):
        #show study setup
        self._init_study_sizer()
        #update dbs with whatever wiz captured
        expItem = self.SettingsInfo.SubmitExp()
        self.StudyInfo.SubmitStudy(expItem)
        #enable file queue page
        self.root.plFileHolder.Enable(True)
        #move to file queue page
        self.root.listBook.SetSelection(2)
        
class FileHandlingPanel(wx.Panel):
    def _init_sizer(self):
        #sizer for queue panel
        self.fqSizer = wx.GridBagSizer(hgap=4, vgap=4)
        self.fqSizer.SetCols(4)
        self.fqSizer.SetRows(4)
        
        self.fqSizer.AddWindow(self.nbFileHolder, (0, 0), border=0, flag=wx.EXPAND, 
              span=(1, 4))
        self.fqSizer.AddSpacer(wx.Size(4, 4), (1, 0), border=0, flag=0, span=(1,4))
        self.fqSizer.AddWindow(self.btnLoad, (2, 2), border=0, flag=wx.EXPAND, 
              span=(1, 1))
        self.fqSizer.AddWindow(self.btnSendAll, (2, 3), border=0, flag=wx.EXPAND, 
              span=(1, 1))
        
        self.fqSizer.AddGrowableRow(0)
        self.fqSizer.AddGrowableCol(0)
#        self.fqSizer.AddGrowableCol(1)
#        self.fqSizer.AddGrowableCol(2)
#        self.fqSizer.AddGrowableCol(3)
        
        self.SetSizer(self.fqSizer)
        
    def _init_ctrls(self, prnt, root):
        wx.Panel.__init__(self, id=wx.NewId(), name='FileHandlingPanel', parent=prnt,
              pos=wx.Point(-12, 22), size=wx.Size(1024, 599), style=wx.TAB_TRAVERSAL)
        self.SetAutoLayout(True)
        self.SetToolTipString('')
        
        #load and send buttons
        self.btnLoad = wx.Button(self, LoadId, label='Load')
        self.btnLoad.Bind(wx.EVT_BUTTON, self.OnBtnLoad, id=LoadId)
        
        self.btnSendAll = wx.Button(self, SendAllId, label='Send All')
        self.btnSendAll.Bind(wx.EVT_BUTTON, self.OnBtnSendAll, id=SendAllId)
#        self.btnSendAll.Bind(wx.EVT_BUTTON, prnt.GetParent().GetParent().root.Send, id=SendAllId)
        
        #notebook for holding acquire, queue, fail nbs
        self.nbFileHolder = wx.Notebook(self, -1, style=0)
        self.nbFileHolder.SetBackgroundColour((218,218,218))
        
        #panel for holding acquired files
        self.tbFileAcquire = Listbook(self.nbFileHolder, root.statusbar)        
        
        #notebook for holding queued files
        self.tbFileQueue = Listbook(self.nbFileHolder, root.statusbar)
        
        #notebook for holding failed files
        self.tbFileFail = Listbook(self.nbFileHolder, root.statusbar)
        
        #add pages to nb
        self.nbFileHolder.AddPage(self.tbFileAcquire, 'Acquired', True)
        self.nbFileHolder.AddPage(self.tbFileQueue, 'Queued', False)
        self.nbFileHolder.AddPage(self.tbFileFail, 'Failed', False)
        
        self._init_sizer()
    
    def __init__(self, parent, root):
        self._init_ctrls(parent, root)
        
        self.root = root
        
    def OnBtnLoad(self, event):
        #load a bunch of files manually
        dlg = wx.FileDialog(self, style=wx.FD_MULTIPLE | wx.FD_OPEN)
        try:
            if dlg.ShowModal() == wx.ID_OK:
                files = dlg.GetPaths()
                for each in files:
                    self.CreateAcquirePage(each)
                    self.nbFileHolder.Layout()
        finally:
            dlg.Destroy()
    
    def OnBtnSendAll(self, event):
        #send all queued files 
        for i in range(self.tbFileAcquire.GetCount()):
            self.root.sendThread.SendToServer(self.tbFileAcquire.GetPage(0))
    
    def OnNbRaMenu(self, event):
        #delete all notebook pages
        pages = self.tbFileAcquire.GetCount()
        count = 1
        while count <= pages:
            self.tbFileAcquire.SetSelection(0)
            #delete current notebook page
#            self.tbFileAcquire.DeletePage(self.tbFileAcquire.GetSelection())
            self.root.statusbar.SetStatusText('Acquired: ' + str(self.tbFileAcquire.GetCount()),2)
            count += 1
        
    def CreateAcquirePage(self, file):              
        #create new filemanager page
        FileHandlingPage(self.tbFileAcquire, file, self.root.statusbar.GetStatusText(5),
              self.root.statusbar.GetStatusText(6))
        
        #change status bar text
        self.root.statusbar.SetStatusText('Acquired: ' + str(self.tbFileAcquire.GetCount()),2)
        
        #restore window
        self.root.Show(True)
        self.root.Maximize(0)
    
    def SendToQueue(self, event):
        #get current page
        page = self.tbFileAcquire.GetCurrentPage()
        id = self.tbFileAcquire.GetSelection()
        
        #create new page in queue
        FileHandlingPage(self.tbFileQueue, page.txtFile.GetValue(), page.txtDate.GetValue(), 
              page.txtTime.GetValue(), subbtn=False, desc=page.txtDesc.GetValue(), gauge=True,
              label=page.txtLabel.GetValue(), enable=False, rembtn=False)
        
        #delete acquired notebook page
        self.tbFileAcquire.DeletePage(id)

        #change counters
        self.root.statusbar.SetStatusText('Acquired: ' + str(self.tbFileAcquire.GetCount()),2)
        self.root.statusbar.SetStatusText('Queued: ' + str(self.tbFileQueue.GetCount()),3)
        
class FileHandlingPage(wx.Panel):
    def _init_sizers(self):
        self.gbsFileman = wx.GridBagSizer(hgap=4, vgap=4)
        self.gbsFileman.SetCols(4)
        self.gbsFileman.SetRows(8)
        self.gbsFileman.AddGrowableCol(0)
        self.gbsFileman.AddGrowableCol(1)
        self.gbsFileman.AddGrowableCol(2)
        self.gbsFileman.AddGrowableCol(3)
        self.gbsFileman.Add(wx.StaticText(self,-1,'Current File'), (0, 0), 
              border=0, flag=wx.EXPAND, span=(1, 1))
        self.gbsFileman.AddWindow(self.txtFile, (0, 1), border=0, flag=wx.EXPAND, 
              span=(1, 3))
        self.gbsFileman.Add(wx.StaticText(self,-1,'Label'), (1, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.gbsFileman.AddWindow(self.txtLabel, (1, 1), border=0, flag=wx.EXPAND, 
              span=(1, 3))
        self.gbsFileman.Add(wx.StaticText(self,-1,'Description'), (2, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.gbsFileman.AddWindow(self.txtDesc, (2, 1), border=0, flag=wx.EXPAND, 
              span=(1, 3))
        self.gbsFileman.Add(wx.StaticText(self,-1,'Creation date'), (3, 0), 
              border=0, flag=wx.EXPAND, span=(1, 1))
        self.gbsFileman.AddWindow(self.txtDate, (3, 1), border=0, flag=wx.EXPAND, 
              span=(1, 1))
        self.gbsFileman.Add(wx.StaticText(self,-1,'Creation time'), (3, 2), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.gbsFileman.AddWindow(self.txtTime, (3, 3), border=0, flag=wx.EXPAND, 
              span=(1, 1))
        self.gbsFileman.AddWindow(self.btnSend, (5, 1), border=0, flag=wx.EXPAND, 
              span=(1, 2))
        self.gbsFileman.AddWindow(self.gauge, (6, 1), border=0, flag=wx.EXPAND, 
              span=(1, 2))
        self.gbsFileman.AddWindow(self.btnRemove, (7, 1), border=0, flag=wx.EXPAND, 
              span=(1, 2))
        self.SetSizer(self.gbsFileman)
    
    def _init_ctrls(self, prnt, subbtn, desc, label, enable, gauge, rembtn):
        wx.Panel.__init__(self, id=wx.NewId(), name='FileHandlingPage', parent=prnt,
              pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
        self.SetAutoLayout(True)
        self.SetToolTipString('')
        
        self.txtFile = wx.TextCtrl(self, wx.NewId())
        self.txtFile.SetBackgroundColour((218,218,218))
        self.txtFile.Enable(False)
        
        self.txtDesc = wx.TextCtrl(self, wx.NewId(), desc)
        self.txtDesc.SetBackgroundColour((218,218,218))
        self.txtDesc.Enable(enable)
        
        self.txtLabel = wx.TextCtrl(self, wx.NewId(), label)
        self.txtLabel.SetBackgroundColour((218,218,218))
        self.txtLabel.Enable(enable)
        
        if enable:
            self.txtDesc.SetBackgroundColour((255,255,255))
            self.txtLabel.SetBackgroundColour((255,255,255))
            
        self.txtDate = wx.TextCtrl(self, wx.NewId())
        self.txtDate.SetBackgroundColour((218,218,218))
        self.txtDate.SetEditable(False)
        
        self.txtTime = wx.TextCtrl(self, wx.NewId())
        self.txtTime.SetBackgroundColour((218,218,218))
        self.txtTime.SetEditable(False)
        
        self.btnSend = wx.Button(self, SendId, label='Send File To Server')
        self.btnSend.Bind(wx.EVT_BUTTON, prnt.GetParent().GetParent().SendToQueue, id=SendId)
        if not subbtn:
            self.btnSend.Show(False)  
            
        self.btnRemove = wx.Button(self, RemoveId, label='Remove File')          
        self.btnRemove.Bind(wx.EVT_BUTTON, self.OnBtnRemove, id=RemoveId)
        if not rembtn:
            self.btnRemove.Show(False)
            
        self.gauge = wx.Gauge(self, -1)
        if not gauge:
            self.gauge.Show(False)
        
        self._init_sizers()
    
    def __init__(self, parent, file, date, time, subbtn=True, 
                 desc="", label="", enable=True, gauge=False,
                 rembtn=True):
        
        self._init_ctrls(parent, subbtn, desc, label, enable, gauge, rembtn)
        
        self.prnt = parent
        
        self.prnt.AddPage(self, os.path.basename(file))
        self.prnt.Layout()
        
        self.txtFile.SetValue(file)
        self.txtDate.SetValue(date)
        self.txtTime.SetValue(time)
        
        #add label from most recent tab
        if (file not in ['Acquired Files']) & (label == ""):
            self.txtLabel.SetValue(os.path.basename(file))
        
#        #add description from most recent tab
#        cpage = parent.GetSelection()
#        if cpage > 0:
#            self.txtDesc.SetValue(parent.GetPage(cpage-1).txtDesc.GetValue())

    def OnBtnRemove(self, event):
        dlg = wx.MessageDialog(self.prnt, 'Delete this entry from the RamanTap?', 
              'Confirm', wx.YES_NO | wx.ICON_QUESTION)
        try:
            if dlg.ShowModal() == wx.ID_YES:
                #delete a page
                self.prnt.DeletePage(self.prnt.GetSelection())
        finally:
            dlg.Destroy()
        
class LoginManagerPanel(wx.Panel):
    def _init_sizers(self):
        self.fmgrid = wx.GridBagSizer(hgap=4, vgap=4)
        self.fmgrid.SetCols(4)
        self.fmgrid.SetRows(6)
        self.fmgrid.AddGrowableCol(0)
        self.fmgrid.AddGrowableCol(1)
        self.fmgrid.AddGrowableCol(2)
        self.fmgrid.AddGrowableCol(3)
        
        self.fmgrid.AddWindow(self.btnDir, (0, 0), border=0, flag=wx.EXPAND, span=(1, 4))
        self.fmgrid.AddSpacer(wx.Size(4, 4), (1,0), border=0, flag=0, span=(1, 4))
        self.fmgrid.Add(wx.StaticText(self,-1,'Hostname'), (2, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.fmgrid.AddWindow(self.txtHost, (2, 1), border=0, flag=wx.EXPAND, span=(1, 3))
        self.fmgrid.Add(wx.StaticText(self,-1,'Resource'), (3, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.fmgrid.AddWindow(self.txtResource, (3, 1), border=0, flag=wx.EXPAND, span=(1, 3))
        self.fmgrid.Add(wx.StaticText(self,-1,'Username'), (4, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.fmgrid.AddWindow(self.txtUser, (4, 1), border=0, flag=wx.EXPAND, span=(1, 3))
        self.fmgrid.Add(wx.StaticText(self,-1,'Password'), (5, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.fmgrid.AddWindow(self.txtPass, (5, 1), border=0, flag=wx.EXPAND, span=(1, 3))
        self.fmgrid.Add(wx.StaticText(self,-1,'Poll Interval (s)'), (6, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.fmgrid.AddWindow(self.spnPollInterval, (6, 1), border=0, flag=wx.EXPAND, span=(1, 1))
        self.fmgrid.AddWindow(self.btnStartSession, (6, 3), border=0, flag=wx.EXPAND, span=(1, 1))
        
        self.SetSizer(self.fmgrid)
        
    def _init_ctrls(self, prnt):
        wx.Panel.__init__(self, id=-1, name='LoginManagerPanel', parent=prnt,
              pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
        self.Bind(wx.EVT_TEXT, self.OnTxtFileMan, id=TxtFileManId)
        self.SetConstraints(LayoutAnchors(self, True, True, True, True))        
        self.SetAutoLayout(True)
        self.SetToolTipString('')
        
        self.btnDir = wx.lib.filebrowsebutton.DirBrowseButton(self, wx.NewId(), 
              wx.Point(64, 32),wx.Size(296, 27),style=wx.TAB_TRAVERSAL,
              labelText='Target directory:',changeCallback = self.dbbCallback)
        
        self.txtHost = wx.TextCtrl(self, TxtFileManId)
        
        self.txtResource = wx.TextCtrl(self, TxtFileManId)
        
        self.txtUser = wx.TextCtrl(self, TxtFileManId)
        
        self.txtPass = wx.TextCtrl(self, TxtFileManId, style=wx.TE_PASSWORD)
        
        self.spnPollInterval = wx.SpinCtrl(self, PollIntId, "")
        self.spnPollInterval.SetRange(1,20)
        self.spnPollInterval.SetValue(3)
        self.spnPollInterval.Bind(wx.EVT_SPIN,self.OnSpnPollInterval,id=PollIntId)
        
        self.btnStartSession = wx.lib.buttons.GenToggleButton(id=StartSessId,
              label='Start Session', name='btnStartSession', parent=self)
        self.btnStartSession.Bind(wx.EVT_BUTTON,self.OnBtnStartSession,
              id=StartSessId)
        
        self._init_sizers()
    
    def __init__(self, parent, root):
        self._init_ctrls(parent)
        
        self.root = root
        
    def OnTxtFileMan(self, event):
        #stop directory polling
        if self.root.pollThread.IsRunning():
            wx.Yield()
            self.root.pollThread.Stop()
            while self.root.pollThread.IsRunning():
                time.sleep(0.1)
        
    def OnSpnPollInterval(self, event):
        self.StopDirPoll()
        self.root.pollThread = PollDirThread(self.root, self.spnPollInterval.GetValue())
    
    def OnBtnStartSession(self, event):
        if self.btnStartSession.GetValue():
            #try and connect to dbs
            client = self.root.TapConnect()
            #initialise application
            if client != None:
                if not self.root.pollThread.IsRunning():
                    self.root.Initialise()
                if self.root.pollThread.IsRunning():
                    self.root.StatusEnabled()
                    self.root.listBook.SetSelection(1)
                else:
                    self.root.pollThread.Stop()
                    self.root.StatusDisabled()
                    self.root.plFileHolder.Enable(False)
            else:
                self.root.StatusDisabled()
                self.root.plFileHolder.Enable(False)
        else:
            #stop dir polling
            self.StopDirPoll()
            self.root.StatusDisabled()
            self.root.plFileHolder.Enable(False)
                
    def StopDirPoll(self):
        #stop dir polling
        wx.Yield()
        self.root.pollThread.Stop()
        while self.root.pollThread.IsRunning():
            time.sleep(0.1)
        
    def dbbCallback(self, event):
        #stop dir polling
        self.StopDirPoll()
        #start polling again
        self.root.pollThread = PollDirThread(self.root, self.spnPollInterval.GetValue())
        self.root.pollThread.Start()
        #msg to statusbar
        self.root.statusbar.SetStatusText('Polling Directory Changed',0)
        time.sleep(2)
        self.root.statusbar.SetStatusText('RamanTap Active',0)
                
class SettingsPanel(wx.Panel):
    def _init_sizers(self):
        self.isgrid = wx.GridBagSizer(hgap=4, vgap=4)
        self.isgrid.SetCols(4)
        self.isgrid.SetRows(14)
        self.isgrid.AddGrowableCol(0)
        self.isgrid.AddGrowableCol(1)
        self.isgrid.AddGrowableCol(2)
        self.isgrid.AddGrowableCol(3)

        self.isgrid.AddWindow(self.cbExperiments, (0, 0), border=0, flag=wx.EXPAND, span=(1, 4))
        self.isgrid.AddWindow(self.cbSettings, (1, 0), border=0, flag=wx.EXPAND, span=(1, 4))
        self.isgrid.AddWindow(self.chInstrument, (2, 0), border=0, flag=wx.EXPAND, span=(1, 4))
        self.isgrid.Add(wx.StaticText(self,-1,'Integration Time (s)'), (3, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.txtIntTime, (3, 1), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Accumulations'), (3, 2), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.spnAccumulations, (3, 3), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Microscope Objective'), (4, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.chObjective, (4, 1), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Power at Sample (mW)'), (4, 2), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.spnPowerAtSample, (4, 3), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Detector Gain'), (5, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.chGain, (5, 1), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Min. Raman Shift (cm-1)'), (6, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.txtMinShift, (6, 1), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Max. Raman Shift (cm-1)'), (6, 2), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.txtMaxShift, (6, 3), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddSpacer(wx.Size(4, 4), (7, 0), border=0, flag=0, span=(1,4))
        self.isgrid.AddWindow(self.stSersHead, (8, 0), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Substrate Description'), (9, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.txtSersSub, (9, 1), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Substrate Conc. (%v/v)'), (9, 2), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.txtSubConc, (9, 3), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Aggregating Agent'), (10, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.txtAggAgent, (10, 1), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.Add(wx.StaticText(self,-1,'Agg. Conc. (mM)'), (10, 2), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.txtAggConc, (10, 3), border=0, flag=wx.EXPAND, span=(1, 1))
        self.isgrid.AddWindow(self.txtReference, (11, 0), border=0, flag=wx.EXPAND, span=(2, 4))
        
        self.SetSizer(self.isgrid)
        
    def _init_ctrls(self, prnt):
        wx.Panel.__init__(self, id=-1, name='SettingsPanel', parent=prnt,
              pos=wx.Point(0,0), size=wx.Size(450, 430), style=wx.TAB_TRAVERSAL)
        self.SetConstraints(LayoutAnchors(self, True, True, True, True))
        self.SetAutoLayout(True)
        self.SetToolTipString('')
        
        self.cbExperiments = wx.ComboBox(choices=['Select or enter new experiment name...'], 
              id=ExpsComboId, name='cbExperiments', parent=self, pos=wx.Point(248, 96),
              size=wx.Size(130, 21), style=wx.TE_PROCESS_ENTER, 
              value='Select or enter new experiment name...')
        self.cbExperiments.Bind(wx.EVT_COMBOBOX, self.OnCbExperiments, id=ExpsComboId)
        self.cbExperiments.Bind(wx.EVT_TEXT_ENTER, self.OnCbExperimentsEnter,
              id=ExpsComboId)
              
        self.cbSettings = wx.ComboBox(choices=['Select or enter new settings identifier...'], 
              id=SetComboId, name='cbSettings', parent=self, pos=wx.Point(248, 96),
              size=wx.Size(130, 21), style=wx.TE_PROCESS_ENTER, 
              value='Select or enter new settings identifier...')
        self.cbSettings.Bind(wx.EVT_COMBOBOX, self.OnCbSettings, id=SetComboId)
        
        self.chInstrument = wx.Choice(self, InstChoiceId, 
              choices=['Select instrument...'])
        self.chInstrument.SetSelection(0)
        
        self.txtIntTime = wx.TextCtrl(self, wx.NewId())
        
        self.spnAccumulations = wx.SpinCtrl(id=wx.NewId(), initial=1, max=10000, 
              min=1, name='spnAccumulations', parent=self, 
              style=wx.SP_ARROW_KEYS)
              
        self.chObjective = wx.Choice(self, wx.NewId(), choices=[])
        self.chObjective.SetSelection(0)
        
        self.spnPowerAtSample = wx.SpinCtrl(id=wx.NewId(), initial=1, max=10000, 
              min=1, name='spnPowerAtSample', parent=self, style=wx.SP_ARROW_KEYS)
        
        self.chGain = wx.Choice(self, wx.NewId(), choices=[''])
        
        self.txtMinShift = wx.TextCtrl(self, wx.NewId())
        
        self.txtMaxShift = wx.TextCtrl(self, wx.NewId())
        
        self.stSersHead = wx.StaticText(self, wx.NewId(), 'SERS Conditions')
        self.stSersHead.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL,
              True, 'MS Shell Dlg 2'))
                
        self.txtSersSub = wx.TextCtrl(self, wx.NewId(), 'None')
        
        self.txtSubConc = wx.TextCtrl(self, wx.NewId(), '0')
        
        self.txtAggAgent = wx.TextCtrl(self, wx.NewId(), 'None')
        
        self.txtAggConc = wx.TextCtrl(self, wx.NewId(), '0')
        
        self.txtReference = wx.TextCtrl(self, wx.NewId(), 
              'Bibliographic Reference')
        
        self._init_sizers()
    
    def __init__(self, parent, root):
        self._init_ctrls(parent)
        
        self.root = root
        
    def SubmitExp(self):
        try:
            #connect
            client = self.root.TapConnect()
            #spectrometer settings id
            setId = client.getDomainName() + '/' + \
                  self.root.plLoginManager.txtResource.GetValue() + \
                  '/Spectrometer Settings/' + \
                  self.root.plLoginManager.txtUser.GetValue() + '/' + \
                  self.cbSettings.GetValue()
            #create instrument settings item if necessary
            if setId not in client.itemFind("ITEM_ID", "<ItemType>Spectrometer Settings</ItemType>"):
                setItem = omixed.OmixedItem()
                setItem.setupNewItem(client, "Spectrometer Settings", self.cbSettings.GetValue(), 
                      "public")
                #instrument
                insId = client.getDomainName() + '/' + \
                      self.root.plLoginManager.txtResource.GetValue() + \
                      '/Spectrometer/' + \
                      self.root.plLoginManager.txtUser.GetValue() + '/' + \
                      self.chInstrument.GetStringSelection()
                setItem.setLink("for instrument", insId)
                #set integration time
                setItem.setAttribute("Spectrometer.integration time",self.txtIntTime.GetValue())
                #set min raman shift
                setItem.setAttribute("Spectrometer.raman shift range.min",self.txtMinShift.GetValue())
                #set max raman shift
                setItem.setAttribute("Spectrometer.raman shift range.max",self.txtMaxShift.GetValue())
                #set accumulations
                setItem.setAttribute("Spectrometer.accumulations",str(self.spnAccumulations.GetValue()))
                #set detector gain 
                setItem.setAttribute("Spectrometer.gain",self.chGain.GetStringSelection())
                #set microscope objective
                setItem.setAttribute("Spectrometer.microscope objective",self.chObjective.GetStringSelection())
                #set power
                setItem.setAttribute("Spectrometer.power at sample",str(self.spnPowerAtSample.GetValue()))
                #set sers substrate
                setItem.setAttribute("SERS.substrate",self.txtSersSub.GetValue())
                #set sers substrate conc
                setItem.setAttribute("SERS.%v/v concentration",self.txtSubConc.GetValue())
                #set aggregatibg agent
                setItem.setAttribute("SERS.aggregating agent",self.txtAggAgent.GetValue())
                #set aggregatibg agent conc
                setItem.setAttribute("SERS.milimolar agent concentration",self.txtAggConc.GetValue())
                #set reference
                setItem.setAttribute("SERS.bibliographic reference",self.txtReference.GetValue())
        
                #create item on dbs
                client.itemCreate(setItem)
                
            #experiment id
            expId = client.getDomainName() + '/' + \
                  self.root.plLoginManager.txtResource.GetValue() + \
                  '/Experiment/' + \
                  self.root.plLoginManager.txtUser.GetValue() + '/' + \
                  self.cbExperiments.GetValue()
            
            #create new experiment if necessary
            if expId not in client.itemFind("ITEM_ID", "<ItemType>Experiment</ItemType>"):
                expItem = omixed.OmixedItem()
                expItem.setupNewItem(client, "Experiment", self.cbExperiments.GetValue(), 
                      "public")
                #link to settings
                expItem.setLink('run with settings', setId)
                #create item on dbs
                client.itemCreate(expItem)
                
            else:
                expItem = client.itemFind(omixed.OmixedQuery.FULL_ITEM_DETAILS,"<ItemID>" + expId + "</ItemID>")[0]
            
            #disconnect
            client.disconnect()
            
            #update controls
            self.Update(expentry=self.cbExperiments.GetValue(), setentry=self.cbSettings.GetValue())
            
            return expItem
            
        except Exception, error:
            raise
            dlg = wx.MessageDialog(self.root.frame, '%s' %str(error), 'Error!', 
                  wx.OK | wx.ICON_ERROR)
            try:
                dlg.ShowModal()
            finally:
                dlg.Destroy()
    
    def OnCbExperiments(self, event):
        #update screen based upon selection
        self.Select(self.cbExperiments,'Experiment', self.cbExperiments.GetStringSelection())
        #disable controls because only one lot of settings can be linked to exp
        self.DisableCtrls()
        
    def OnCbExperimentsEnter(self, event):
        #append entry to list
        self.cbExperiments.Append(self.cbExperiments.GetValue()) 
        #make sure ctrls enabled
        self.EnableCtrls()
        
    def OnCbSettings(self, event):
        self.Select(self.cbSettings, 'Spectrometer Settings', self.cbSettings.GetStringSelection())
    
    def Select(self, combo, item, entry):
        #select entry
        combo.SetStringSelection(entry)
        #connect
        client = self.root.TapConnect()
        #path to selected study item
        itemId = client.getDomainName() + '/' + \
              self.root.plLoginManager.txtResource.GetValue() + '/' + item + '/' + \
              self.root.plLoginManager.txtUser.GetValue() + '/' + \
              entry
        #study item
        iTem = client.itemFind(omixed.OmixedQuery.FULL_ITEM_DETAILS,"<ItemID>" + itemId + "</ItemID>")[0]
        #populate settings fields
        if combo == self.cbSettings:
            #settings choice
            setChoice = self.cbSettings.GetStringSelection()
            #select settings option
            self.cbSettings.SetStringSelection(setChoice)
            #get instrument
            self.chInstrument.SetStringSelection(getName(iTem.getLinks("for instrument")[0]))
            #get integration time
            self.txtIntTime.SetValue(str(iTem.getAttribute("Spectrometer.integration time")))
            #get min raman shift
            self.txtMinShift.SetValue(str(iTem.getAttribute("Spectrometer.raman shift range.min")))
            #get max raman shift
            self.txtMaxShift.SetValue(str(iTem.getAttribute("Spectrometer.raman shift range.max")))
            #get accumulations
            self.spnAccumulations.SetValue(int(iTem.getAttribute("Spectrometer.accumulations")))
            #get detector gain 
            self.chGain.SetStringSelection(iTem.getAttribute("Spectrometer.gain"))
            #get microscope objective
            self.chObjective.SetStringSelection(iTem.getAttribute("Spectrometer.microscope objective"))
            #get power
            self.spnPowerAtSample.SetValue(int(iTem.getAttribute("Spectrometer.power at sample")))
            #get sers substrate
            self.txtSersSub.SetValue(iTem.getAttribute("SERS.substrate"))
            #get sers substrate conc
            self.txtSubConc.SetValue(str(iTem.getAttribute("SERS.%v/v concentration")))
            #get aggregatibg agent
            self.txtAggAgent.SetValue(iTem.getAttribute("SERS.aggregating agent"))
            #get aggregatibg agent onc
            self.txtAggConc.SetValue(str(iTem.getAttribute("SERS.milimolar agent concentration")))
            #get reference
            self.txtReference.SetValue(iTem.getAttribute("SERS.bibliographic reference"))
        
        elif combo == self.cbExperiments:
            #settings choice
            setChoice = getName(iTem.getLinks("run with settings")[0])
            #reset everything
            self.Update(setentry=setChoice)
                    
        #disconnect
        client.disconnect()
    
    def Update(self, expentry=None, setentry=None):
        #connect
        client = self.root.TapConnect()
        try:
            #get microscope obj list options
            self.chObjective.Clear()
            self.chObjective.Append("None")
            self.chObjective.Append("5")
            self.chObjective.Append("10")
            self.chObjective.Append("20")
            self.chObjective.Append("40")
            self.chObjective.Append("50")
            self.chObjective.Append("100")
            
            #get detector gain list options
            self.chGain.Clear()
            self.chGain.Append('High')
            self.chGain.Append('Low')
            
            #get list of instruments from dbs
            self.chInstrument.Clear()
            self.chInstrument.Append('Select spectrometer...')
            instIds = client.itemFind("ITEM_ID", "<ItemType>Spectrometer</ItemType>")
            for each in instIds: 
                self.chInstrument.Append(getName(each))
            self.chInstrument.SetSelection(0)
                
            self.cbSettings.Clear()
            self.cbSettings.Append('Select or enter new settings identifier...')
            setIds = client.itemFind("ITEM_ID", "<ItemType>Spectrometer Settings</ItemType>")
            for each in setIds: 
                self.cbSettings.Append(getName(each))
            self.cbSettings.SetSelection(0)
                
            #select entries
            if expentry != None:
                self.Select(self.cbExperiments,'Experiment',expentry)
            if setentry != None:
                self.Select(self.cbSettings,'Spectrometer Settings',setentry)
            else:
                #reset controls
                self.SetDefaultEntries()
            
#            self.SetDefaultEntries()
            #disconnect
            client.disconnect()
        
        except Exception, error:
            raise
            dlg = wx.MessageDialog(self.root.frame, '%s' %str(error), 'Error!', 
                  wx.OK | wx.ICON_ERROR)
            try:
                dlg.ShowModal()
#                client.disconnect()
            finally:
                #disconnect
                dlg.Destroy()
    
    def SetDefaultEntries(self):
        #set some defaults
        self.txtIntTime.SetValue('0')
        self.spnAccumulations.SetValue(0)              
        self.chObjective.SetSelection(0)
        self.spnPowerAtSample.SetValue(0)
        self.chGain.SetSelection(0)
        self.txtMinShift.SetValue('0')
        self.txtMaxShift.SetValue('0')
        self.txtSersSub.SetValue('None')
        self.txtSubConc.SetValue('0')
        self.txtAggAgent.SetValue('None')
        self.txtAggConc.SetValue('0')
        self.txtReference.SetValue('None')
    
    def EnableCtrls(self):
        #enable controls
        self.cbSettings.Enable(True)
        self.chInstrument.Enable(True)
        self.txtIntTime.Enable(True)
        self.spnAccumulations.Enable(True)              
        self.chObjective.Enable(True)
        self.spnPowerAtSample.Enable(True)
        self.chGain.Enable(True)
        self.txtMinShift.Enable(True)
        self.txtMaxShift.Enable(True)
        self.txtSersSub.Enable(True)
        self.txtSubConc.Enable(True)
        self.txtAggAgent.Enable(True)
        self.txtAggConc.Enable(True)
        self.txtReference.Enable(True)
    
    def DisableCtrls(self):
        #disable controls
        self.cbSettings.Enable(False)
        self.chInstrument.Enable(False)
        self.txtIntTime.Enable(False)
        self.spnAccumulations.Enable(False)              
        self.chObjective.Enable(False)
        self.spnPowerAtSample.Enable(False)
        self.chGain.Enable(False)
        self.txtMinShift.Enable(False)
        self.txtMaxShift.Enable(False)
        self.txtSersSub.Enable(False)
        self.txtSubConc.Enable(False)
        self.txtAggAgent.Enable(False)
        self.txtAggConc.Enable(False)
        self.txtReference.Enable(False)
        
class StudyPanel(wx.Panel):
    def _init_sizers(self):
        self.stgrid = wx.GridBagSizer(hgap=4, vgap=4)
        self.stgrid.SetCols(4)
        self.stgrid.SetRows(4)
        self.stgrid.AddGrowableCol(0)
        
        self.stgrid.AddWindow(self.chStudy, (0, 0), border=0, flag=wx.EXPAND, 
              span=(1, 4))
        self.stgrid.AddWindow(self.chStudyType, (1, 0), border=0, flag=wx.EXPAND, 
              span=(1, 4))
        self.stgrid.Add(wx.StaticText(self,-1,'Description'), (2, 0), border=0, 
              flag=wx.EXPAND, span=(1, 1))
        self.stgrid.AddWindow(self.txtStudyDesc, (3, 0), border=0, flag=wx.EXPAND, 
              span=(4, 4))
        
        self.SetSizer(self.stgrid)
        
    def _init_ctrls(self, prnt):
        wx.Panel.__init__(self, id=-1, name='StudyPanel', parent=prnt,
              pos=wx.Point(0, 0), size=wx.Size(300, 430), style=wx.TAB_TRAVERSAL)
        self.SetConstraints(LayoutAnchors(self, True, True, True, True))
        self.SetAutoLayout(True)
        self.SetToolTipString('')
        
        self.chStudy = wx.ComboBox(choices=[''], id=StudyChId, name='chStudy', 
              parent=self, style=wx.TE_PROCESS_ENTER)
        self.chStudy.Bind(wx.EVT_COMBOBOX, self.OnChStudy, id=StudyChId)
        self.chStudy.SetSelection(0)
        
        self.chStudyType = wx.Choice(self, wx.NewId(), choices=[''])
        self.chStudyType.SetSelection(0)
        
        self.txtStudyDesc = wx.TextCtrl(self, wx.NewId(), size=wx.Size(100,100),
              style = wx.TE_MULTILINE | wx.TE_WORDWRAP, 
              value='Enter description of study')
        
        self._init_sizers()
    
    def __init__(self, parent, root):
        self._init_ctrls(parent)
        
        self.root = root
        
    def SubmitStudy(self, expItem):
        try:
            #connect
            client = self.root.TapConnect()
            
            #study id
            studyId = client.getDomainName() + '/' + \
                  self.root.plLoginManager.txtResource.GetValue() + \
                  '/Study/' + \
                  self.root.plLoginManager.txtUser.GetValue() + '/' + \
                  self.chStudy.GetStringSelection()
            
            #create new experiment if necessary
            if studyId not in client.itemFind("ITEM_ID", "<ItemType>Study</ItemType>"):
                #create new dbs entry
                studyItem = omixed.OmixedItem()
                studyItem.setupNewItem(client, "Study", self.chStudy.GetValue(), 
                      "public")
                studyItem.setAttribute ("Type of study", self.chStudyType.GetStringSelection())
                studyItem.setAttribute ("description", self.txtStudyDesc.GetValue())
                #create item on dbs
                client.itemCreate(studyItem)
                
            else:
                studyItem = client.itemFind(omixed.OmixedQuery.FULL_ITEM_DETAILS,"<ItemID>" + studyId + "</ItemID>")[0]
                
            #link experiment to study
            if studyItem.getLinks("comprised of experiments") != None:
                if expItem.itemID not in studyItem.getLinks("comprised of experiments"):
                    studyItem.setLink("comprised of experiments", expItem.itemID)
                    #update item on dbs
                    client.lockAcquire(studyItem.itemID)
                    client.itemUpdate(studyItem)
            else:
                studyItem.setLink("comprised of experiments", expItem.itemID)
                #update item on dbs
                client.lockAcquire(studyItem.itemID)
                client.itemUpdate(studyItem)
                
            #disconnect
            client.disconnect()
            
            #update controls
            self.Update(self.chStudy.GetValue())
            
        except Exception, error:
            raise
            dlg = wx.MessageDialog(self.root.frame, '%s' %str(error), 'Error!', 
                  wx.OK | wx.ICON_ERROR)
            try:
                dlg.ShowModal()
            finally:
                dlg.Destroy()
    
    def OnChStudy(self, event):
        self.Select(self.chStudy.GetStringSelection())
    
    def Select(self, entry):
        #select entry
        self.chStudy.SetStringSelection(entry)
        #connect
        client = self.root.TapConnect()
        #path to selected study item
        studyItemId = client.getDomainName() + '/' + \
              self.root.plLoginManager.txtResource.GetValue() + '/Study/' + \
              self.root.plLoginManager.txtUser.GetValue() + '/' + \
              entry
        #study item
        studyItem = client.itemFind(omixed.OmixedQuery.FULL_ITEM_DETAILS,"<ItemID>" + studyItemId + "</ItemID>")[0]
        #select study type
        self.chStudyType.SetStringSelection(studyItem.getAttribute("Type of study"))
        #select study type
        self.txtStudyDesc.SetValue(studyItem.getAttribute("description"))
        #populate experiment cb with exps related to study
        currExp = self.root.SettingsWiz.SettingsInfo.cbExperiments.GetStringSelection()
        
        self.root.SettingsWiz.SettingsInfo.cbExperiments.Clear()
        self.root.SettingsWiz.SettingsInfo.cbExperiments.Append('Select or enter new experiment name...')
        self.root.SettingsWiz.SettingsInfo.cbExperiments.SetSelection(0)
        
        #get experiments
        expIds = studyItem.getLinks("comprised of experiments")
        expList = []
        if expIds not in [None]:
            for each in expIds: 
                self.root.SettingsWiz.SettingsInfo.cbExperiments.Append(getName(each))
                expList.append(getName(each))
        
        if currExp in expList:
            self.root.SettingsWiz.SettingsInfo.cbExperiments.SetStringSelection(currExp)
        
    def Update(self, entry=None):
        #update study panel contets from dbs
        client = self.root.TapConnect()
        
        #clear current list
        self.chStudy.Clear()
        
        try:
            #set list of studies
            studyIds = client.itemFind("ITEM_ID", "<ItemType>Study</ItemType>")
            self.chStudy.Append('Select or enter new study name...')
            self.chStudy.SetSelection(0)
            for each in studyIds: 
                self.chStudy.Append(getName(each))
            
            #get study types
            self.chStudyType.Clear()
            self.chStudyType.Append('Select the type of study to be performed...')
            self.chStudyType.SetSelection(0)
            self.chStudyType.Append("categorical")
            self.chStudyType.Append("calibration")
            self.chStudyType.Append("exploratory")
            self.chStudyType.Append("mapping")
            self.chStudyType.Append("standards")
            self.chStudyType.Append("structural biology")
            
            #clear description
            self.txtStudyDesc.SetValue('Enter description of study')
            
            #select entry
            if entry != None:
                self.Select(entry)
        
        except Exception, error:
            raise
            dlg = wx.MessageDialog(self.root.frame, '%s' %str(error), 'Error!', 
                  wx.OK | wx.ICON_ERROR)
            try:
                dlg.ShowModal()
            finally:
                dlg.Destroy()

class TaskBarIcon(wx.TaskBarIcon):
    def __init__(self, prnt):
        wx.TaskBarIcon.__init__(self)
        self.SetIcon(wx.Icon(name='images/tap.ico', type=wx.BITMAP_TYPE_ICO), 
              tooltip='RamanTap')
        self.Bind(wx.EVT_TASKBAR_RIGHT_UP, self.OnTaskBarRight, id=wx.NewId())
        self.Bind(wx.EVT_TASKBAR_LEFT_UP, self.OnTaskBarLeft, id=wx.NewId())
        self.root = prnt
        
    def OnTaskBarRight(self, event):
        self.mnu = self.CreatePopupMenu()
        
    def OnTaskBarLeft(self, event):
        if self.root.IsIconized():
           self.root.Iconize(False)
        if not self.IsShown():
           self.root.Show(True)
           self.root.Raise()
        
    def CreatePopupMenu(self):
        #create taskbar menu
        menu = wx.Menu(title='')
        menu.Append(help='', id=AboutId, kind=wx.ITEM_NORMAL,
              text='About')
        menu.Bind(wx.EVT_MENU, self.OnMnuAbout,id=AboutId)
        menu.Append(help='', id=RestoreId, kind=wx.ITEM_NORMAL,
              text='Restore')
        menu.Bind(wx.EVT_MENU, self.OnMnuRestore,id=RestoreId)
        menu.Append(help='', id=ExitId, kind=wx.ITEM_NORMAL,
              text='Exit')
        menu.Bind(wx.EVT_MENU, self.OnMnuExit, id=ExitId)
        
        return menu
    
    def OnMnuAbout(self, event):
        #do an about box thing
        info = wx.AboutDialogInfo()
        info.Name = "RamanTap"
        info.Version = "0.0.1"
        info.SetIcon(wx.Icon(name='images/tap.ico', type=wx.BITMAP_TYPE_ICO))
        info.Copyright = "(C) 2009 Roger Jarvis & Giles Velarde"
        info.Description = wx.lib.wordwrap.wordwrap(
            "\nA program for managing spectral data collection "
            "\n\nEmail: roger.jarvis@manchester.ac.uk",
            350, wx.ClientDC(self))
        wx.AboutBox(info)
        
    def OnMnuRestore(self, event):
        self.root.Show(True)
        self.root.Maximize(0)
    
    def OnMnuExit(self, event):
        self.Exit()
    
class TapFrame(wx.Frame):
    def _init_sizers(self):
        #frame sizer for panel
        self.vsizer = wx.BoxSizer(wx.VERTICAL)
        self.vsizer.Add(self.listBook, 1, wx.EXPAND)
        self.frsizer = wx.BoxSizer(wx.HORIZONTAL)
        self.frsizer.Add(self.vsizer, 1, wx.EXPAND)
        
        self.SetSizer(self.frsizer)
        
    def _init_ctrls(self, prnt):
        wx.Frame.__init__(self, id=-1, title='RamanTap', parent=prnt,
              size=(800,426), style=wx.DEFAULT_FRAME_STYLE)
        self.Center(wx.BOTH)
        self.SetBackgroundColour(wx.Colour(218,218,218))
        self.SetAutoLayout(True)
        self.SetMinSize(wx.Size(800,426))
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_ICONIZE, self.OnMinimize)
        
        #setup icon object
        icon = wx.Icon("images/tap.ico", wx.BITMAP_TYPE_ICO)
        self.SetIcon(icon)
        
        #create statusbar
        self.statusbar = self.CreateStatusBar(7, wx.ST_SIZEGRIP)
        self.statusbar.SetStatusWidths([-1,280,80,80,80,80,80])
        self.statusbar.SetStatusText('Ready',0)
        self.statusbar.SetStatusText('Acquired: 0',2)
        self.statusbar.SetStatusText('Queued: 0',3)
        self.statusbar.SetStatusText('Failed: 0',4)
        self.statusbar.Bind(wx.EVT_SIZE, self.OnSbSize)
        
        #error list
        self.errorlist = wx.Choice(self.statusbar, -1, choices=['Omixed Errors'])
        self.errorlist.SetSelection(0)
        
        #resize errorlist
        rect = self.statusbar.GetFieldRect(1)
        self.errorlist.SetPosition((rect.x+2, rect.y+2))
        self.errorlist.SetSize((rect.width-4, rect.height-4))
        
        #setup taskbar icon
        self.tbicon = TaskBarIcon(self)
        
        #listbook for prettying up
        self.listBook = wx.Listbook(self, id=-1, style=wx.LB_LEFT)
        
        # make an image list using the LBXX images
        il = wx.ImageList(32, 32)
        il.Add(wx.Bitmap('images/system-users.png',wx.BITMAP_TYPE_PNG))
        il.Add(wx.Bitmap('images/preferences-system.png',wx.BITMAP_TYPE_PNG))
        il.Add(wx.Bitmap('images/folder-remote.png',wx.BITMAP_TYPE_PNG))
        self.listBook.AssignImageList(il)
        
        #login panel
        self.plLoginManager = LoginManagerPanel(self.listBook, self)
        
        #settings wizard
        self.SettingsWiz = SettingsWizard(self.listBook, self)
        self.SettingsWiz.Enable(False)
        
        #panel for holding queue ctrls
        self.plFileHolder = FileHandlingPanel(self.listBook, self)
        self.plFileHolder.Enable(False)
        
        # Now make a connection panel for the list book
        self.listBook.AddPage(self.plLoginManager, "Connection Details", imageId=0)
        self.listBook.AddPage(self.SettingsWiz, "Experiment Details", 
              imageId=1)
        self.listBook.AddPage(self.plFileHolder, "File Queue", imageId=2)
        
        #create file send to server thread
        self.sendThread = ClearQueueThread(self, self.plFileHolder.tbFileQueue)
        self.sendThread.Start()
        
        #create dir polling thread 
        self.pollThread = PollDirThread(self, self.plLoginManager.spnPollInterval.GetValue())
        
        #load previous settings
        self.LoadSettings()

        #set date/time
        self.SetDateTime()
        
        #start clock
        self.t1 = wx.Timer(self)
        
        #bind timer event for checking files and date/time
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.t1)
        self.t1.Start(1000, wx.TIMER_CONTINUOUS)
        
        #bind file update event
        self.Bind(EVT_UPDATE_NOTEBOOK, self.OnNewFile)
        
        self._init_sizers()
        
    def __init__(self, parent):
        self._init_ctrls(parent)
        
        #prompt for password
        if self.plLoginManager.txtUser.GetValue() != '':
            dlg = wx.TextEntryDialog(self, 'Enter Password for ' + self.plLoginManager.txtUser.GetValue(),
                  'Logon to ' + self.plLoginManager.txtHost.GetValue(), style=wx.TE_PASSWORD | 
                  wx.OK | wx.CANCEL)
            try:
                if dlg.ShowModal() == wx.ID_OK:
                    self.plLoginManager.txtPass.SetValue(dlg.GetValue())
                    #initialise application
                    self.Initialise()  
                    #connection on
                    self.StatusEnabled()
                    #move to exp details page
                    self.listBook.SetSelection(1)
            except:
                #connection off
                self.StatusDisabled()
            finally:
                dlg.Destroy()

    def Initialise(self):
        #get info from dbs
        self.SettingsWiz.StudyInfo.Update()
        self.SettingsWiz.SettingsInfo.Update()
        #poll directory
        self.pollThread.Start()
    
    def StatusDisabled(self):
        #change button label & value
        self.plLoginManager.btnStartSession.SetValue(False)
        self.plLoginManager.btnStartSession.SetLabel('Start Session')
        #disable settings panel
        self.SettingsWiz.Enable(False)
        #status text
        self.statusbar.SetStatusText('RamanTap Inactive', 0)
    
    def StatusEnabled(self):
        #change button label & value
        self.plLoginManager.btnStartSession.SetValue(True)
        self.plLoginManager.btnStartSession.SetLabel('Stop Session')     
        #enable settings panel
        self.SettingsWiz.Enable(True)       
        #status text
        self.statusbar.SetStatusText('RamanTap Active', 0)      
                    
    def OnTimer(self, event):
        #set date/time
        self.SetDateTime()
            
    def OnNewFile(self, event):
        #check for new files
        f = os.path.join(self.plLoginManager.btnDir.GetValue(),event.file)
        #create new notebook page
        self.plFileHolder.CreateAcquirePage(f)
    
    def SetDateTime(self):
        #update date/time ctrls
        date = string.split(datetime.datetime.isoformat(datetime.datetime.today()),'T')
        self.statusbar.SetStatusText(date[0],5)
        self.statusbar.SetStatusText(string.split(date[1],'.')[0],6)
        
    def OnClose(self, event):
        self.Exit()
    
    def Exit(self):
        #stop timer
        self.t1.Stop()
        #save current settings
        self.SaveSettings()
        #make sure dir polling stopped
        wx.Yield()
        self.pollThread.Stop()
        #stop sending files
        self.sendThread.Stop()
        #graceful
        while self.pollThread.IsRunning() | self.sendThread.IsRunning():
#            print self.pollThread.IsRunning()
#            print self.sendThread.IsRunning()
#            print
            time.sleep(0.1)
        #close program
        self.tbicon.Destroy()
        self.Destroy()
    
    def OnMinimize(self, event):
        self.Show(False)
    
    def TapConnect(self):
        #connect to dbs
        client = None
        try:
            client = omixed.OmixedClient(self.plLoginManager.txtHost.GetValue())
            client.connect(self.plLoginManager.txtResource.GetValue(), self.plLoginManager.txtUser.GetValue(),
                  self.plLoginManager.txtPass.GetValue())
            return client
        
        except Exception, error:
            raise
            dlg = wx.MessageDialog(self, '%s' %str(error), 'Error!', 
                  wx.OK | wx.ICON_ERROR)
            try:
                dlg.ShowModal()
            finally:
                dlg.Destroy()
        
    def SaveSettings(self):
        #save current settings
        if self.plLoginManager.txtHost.GetValue() != '':
            f = file('settings.ini','w')
            f.writelines('#directory\n' + self.plLoginManager.btnDir.GetValue() + '\n')
            f.writelines('#host\n' + self.plLoginManager.txtHost.GetValue() + '\n')
            f.writelines('#resource\n' + self.plLoginManager.txtResource.GetValue() + '\n')
            f.writelines('#user\n' + self.plLoginManager.txtUser.GetValue() + '\n')
            f.close()
    
    def LoadSettings(self):
        #load previous settings
        files = os.listdir(os.getcwd())
        if 'settings.ini' in files:
            f = file('settings.ini','r')
            t = f.readlines()
            count = 0
            for each in t:
                if count == 1:
                    self.plLoginManager.btnDir.SetValue(string.split(each,'\n')[0], 
                          callBack=0)
                elif count == 3:
                    self.plLoginManager.txtHost.SetValue(string.split(each,'\n')[0])
                elif count == 5:
                    self.plLoginManager.txtResource.SetValue(string.split(each,'\n')[0])
                elif count == 7:
                    self.plLoginManager.txtUser.SetValue(string.split(each,'\n')[0])
                count += 1
    
    def OnSbSize(self, event):
        #resize gauge
        rect = self.statusbar.GetFieldRect(1)
        self.errorlist.SetPosition((rect.x+2, rect.y+2))
        self.errorlist.SetSize((rect.width-4, rect.height-4))
        #continue to process event
        event.Skip()
    
class RamanTap(wx.App):
    def OnInit(self):
        frame = TapFrame(parent=None)
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

app = RamanTap(0)
app.MainLoop()
